package com.kexilo.system.management.controller.monitor;

import com.kexilo.core.common.core.web.domain.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.management.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务器监控
 * 
 * @author Kexilo
 */
@RestController
@RequestMapping("/monitor/server")
@Tag(name = "服务器监控", description = "服务器监控相关接口")
public class ServerController {
    
    private static final Logger log = LoggerFactory.getLogger(ServerController.class);

    /**
     * 获取服务器信息
     */
    @PreAuthorize("@ss.hasPermi('monitor:server:list')")
    @GetMapping("/info")
    @Operation(summary = "获取服务器信息", description = "获取服务器基本信息和系统资源使用情况")
    public R<Map<String, Object>> getServerInfo() {
        Map<String, Object> serverInfo = new HashMap<>();
        
        try {
            // CPU信息
            serverInfo.put("cpu", getCpuInfo());
            
            // 内存信息
            serverInfo.put("memory", getMemoryInfo());
            
            // JVM信息
            serverInfo.put("jvm", getJvmInfo());
            
            // 系统信息
            serverInfo.put("system", getSystemInfo());
            
            // 磁盘信息
            serverInfo.put("disk", getDiskInfo());
            
            return R.success(serverInfo);
        } catch (Exception e) {
            log.error("获取服务器信息失败", e);
            return R.fail("获取服务器信息失败");
        }
    }

    /**
     * 获取CPU信息
     */
    private Map<String, Object> getCpuInfo() {
        Map<String, Object> cpuInfo = new HashMap<>();
        
        OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
        
        cpuInfo.put("cpuNum", osBean.getAvailableProcessors());
        cpuInfo.put("loadAverage", osBean.getSystemLoadAverage());
        
        if (osBean instanceof com.sun.management.OperatingSystemMXBean) {
            com.sun.management.OperatingSystemMXBean sunOsBean = 
                (com.sun.management.OperatingSystemMXBean) osBean;
            
            double cpuUsage = sunOsBean.getProcessCpuLoad() * 100;
            cpuInfo.put("used", Math.max(cpuUsage, 0.0));
            cpuInfo.put("sys", sunOsBean.getSystemCpuLoad() * 100);
            cpuInfo.put("free", Math.max(100 - cpuUsage, 0.0));
        }
        
        return cpuInfo;
    }

    /**
     * 获取内存信息
     */
    private Map<String, Object> getMemoryInfo() {
        Map<String, Object> memInfo = new HashMap<>();
        
        OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
        
        if (osBean instanceof com.sun.management.OperatingSystemMXBean) {
            com.sun.management.OperatingSystemMXBean sunOsBean = 
                (com.sun.management.OperatingSystemMXBean) osBean;
            
            long totalMemory = sunOsBean.getTotalPhysicalMemorySize();
            long freeMemory = sunOsBean.getFreePhysicalMemorySize();
            long usedMemory = totalMemory - freeMemory;
            
            memInfo.put("total", formatBytes(totalMemory));
            memInfo.put("used", formatBytes(usedMemory));
            memInfo.put("free", formatBytes(freeMemory));
            memInfo.put("usage", totalMemory > 0 ? (double) usedMemory / totalMemory * 100 : 0);
        }
        
        return memInfo;
    }

    /**
     * 获取JVM信息
     */
    private Map<String, Object> getJvmInfo() {
        Map<String, Object> jvmInfo = new HashMap<>();
        
        RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        
        // JVM基本信息
        jvmInfo.put("name", runtimeBean.getVmName());
        jvmInfo.put("version", runtimeBean.getVmVersion());
        jvmInfo.put("vendor", runtimeBean.getVmVendor());
        jvmInfo.put("uptime", runtimeBean.getUptime());
        jvmInfo.put("startTime", runtimeBean.getStartTime());
        
        // 堆内存
        MemoryUsage heapMemory = memoryBean.getHeapMemoryUsage();
        Map<String, Object> heap = new HashMap<>();
        heap.put("init", formatBytes(heapMemory.getInit()));
        heap.put("used", formatBytes(heapMemory.getUsed()));
        heap.put("committed", formatBytes(heapMemory.getCommitted()));
        heap.put("max", formatBytes(heapMemory.getMax()));
        heap.put("usage", heapMemory.getMax() > 0 ? 
            (double) heapMemory.getUsed() / heapMemory.getMax() * 100 : 0);
        jvmInfo.put("heap", heap);
        
        // 非堆内存
        MemoryUsage nonHeapMemory = memoryBean.getNonHeapMemoryUsage();
        Map<String, Object> nonHeap = new HashMap<>();
        nonHeap.put("init", formatBytes(nonHeapMemory.getInit()));
        nonHeap.put("used", formatBytes(nonHeapMemory.getUsed()));
        nonHeap.put("committed", formatBytes(nonHeapMemory.getCommitted()));
        nonHeap.put("max", formatBytes(nonHeapMemory.getMax()));
        jvmInfo.put("nonHeap", nonHeap);
        
        // 线程信息
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        Map<String, Object> thread = new HashMap<>();
        thread.put("total", threadBean.getThreadCount());
        thread.put("daemon", threadBean.getDaemonThreadCount());
        thread.put("peak", threadBean.getPeakThreadCount());
        jvmInfo.put("thread", thread);
        
        // GC信息
        List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
        Map<String, Object> gc = new HashMap<>();
        long totalGcTime = 0;
        long totalGcCount = 0;
        for (GarbageCollectorMXBean gcBean : gcBeans) {
            totalGcTime += gcBean.getCollectionTime();
            totalGcCount += gcBean.getCollectionCount();
        }
        gc.put("totalTime", totalGcTime);
        gc.put("totalCount", totalGcCount);
        jvmInfo.put("gc", gc);
        
        return jvmInfo;
    }

    /**
     * 获取系统信息
     */
    private Map<String, Object> getSystemInfo() {
        Map<String, Object> sysInfo = new HashMap<>();
        
        OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
        
        sysInfo.put("osName", osBean.getName());
        sysInfo.put("osArch", osBean.getArch());
        sysInfo.put("osVersion", osBean.getVersion());
        
        // Java信息
        sysInfo.put("javaVersion", System.getProperty("java.version"));
        sysInfo.put("javaVendor", System.getProperty("java.vendor"));
        sysInfo.put("javaHome", System.getProperty("java.home"));
        
        // 用户信息
        sysInfo.put("userName", System.getProperty("user.name"));
        sysInfo.put("userDir", System.getProperty("user.dir"));
        sysInfo.put("userTimezone", System.getProperty("user.timezone"));
        
        return sysInfo;
    }

    /**
     * 获取磁盘信息
     */
    private Map<String, Object> getDiskInfo() {
        Map<String, Object> diskInfo = new HashMap<>();
        
        java.io.File[] roots = java.io.File.listRoots();
        long totalSpace = 0;
        long freeSpace = 0;
        
        for (java.io.File root : roots) {
            totalSpace += root.getTotalSpace();
            freeSpace += root.getFreeSpace();
        }
        
        long usedSpace = totalSpace - freeSpace;
        
        diskInfo.put("total", formatBytes(totalSpace));
        diskInfo.put("used", formatBytes(usedSpace));
        diskInfo.put("free", formatBytes(freeSpace));
        diskInfo.put("usage", totalSpace > 0 ? (double) usedSpace / totalSpace * 100 : 0);
        
        return diskInfo;
    }

    /**
     * 格式化字节数
     */
    private String formatBytes(long bytes) {
        if (bytes < 0) return "N/A";
        
        String[] units = {"B", "KB", "MB", "GB", "TB"};
        int unitIndex = 0;
        double size = bytes;
        
        while (size >= 1024 && unitIndex < units.length - 1) {
            size /= 1024;
            unitIndex++;
        }
        
        return String.format("%.2f %s", size, units[unitIndex]);
    }
}

